package com.quantum.gc
{
	import com.pktech.flexutil.configuration.ConfigurationUtil;

	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;

	/**
	 * A memory profiler friendly a property provider that takes advantage of global
	 * instances.
	 *
	 * This property provider will avoid storing the global instance which is provided for
	 * by the globalGetter.  This simplifies the object graph for the memory profiler.
	 */
	public class SharedReference
	{
		private static const GLOBAL_VALUE:Object={};

		//----------------------------------------------------------------
		// Static Properties

		//------------------------------------------------------
		// breakGCGraph
		private static var _breakGCGraph:Boolean=false;

		/**
		 * Property that control if memory profiler gc root graph simplification is enabled.
		 */
		public static function get breakGCGraph():Boolean
		{
			return _breakGCGraph;
		}

		/**
		 * @private
		 */
		public static function set breakGCGraph(value:Boolean):void
		{
			_breakGCGraph=value;
		}

		//----------------------------------------------------------------
		// Member variables

		private var _globalGetter:Function;
		private var _object:*=null;
		private var _className:String=null;
		private var _propName:String=null;

		/**
		 * Constructs a new <code>SharedReference</code> instance.
		 */
		public function SharedReference(token:Class)
		{
			if (token != PrivateConstructorToken)
			{
				throw new Error("SharedReference cannot be instantiated directly.");
			}
		}

		/**
		 * Creates a new <code>SharedReference</code> instance.
		 *
		 * @param globalGetter
		 *    The global instance getter.
		 */
		public static function newReferenceByGetter(globalGetter:Function):SharedReference
		{
			var ref:SharedReference=new SharedReference(PrivateConstructorToken);
			ref._globalGetter=globalGetter;
			return ref;
		}

		/**
		 * Creates a new <code>SharedReference</code> instance.
		 *
		 * @param clazz
		 *    The class defining the instance property.
		 *
		 * @param propName
		 *    The name of the global instance property.
		 */
		public static function newReference(clazz:Class, propName:String="instance"):SharedReference
		{
			var ref:SharedReference=new SharedReference(PrivateConstructorToken);
			if (SharedReference.breakGCGraph)
			{
				ref._className=getQualifiedClassName(clazz);
				ref._propName=propName;
				ref._globalGetter=ref.clazzPropGetter;
			}
			return ref;
		}

		/**
		 * The object to which this <code>SharedReference</code> refers.
		 */
		public function get object():*
		{
			if (_object == GLOBAL_VALUE)
			{
				return _globalGetter();
			}
			return _object;
		}

		/**
		 * @private
		 */
		public function set object(value:*):void
		{
			if (SharedReference.breakGCGraph && _globalGetter() == value)
			{
				_object=GLOBAL_VALUE;
			}
			else
			{
				_object=value;
			}
		}

		private function clazzPropGetter():*
		{
			// ref: http://nondocs.blogspot.com/2007/04/flexhowtoinstantiate-class-from-class.html
			var clazz:Class=getDefinitionByName(_className) as Class;
			return clazz[_propName];
		}
	}
}

// http://livedocs.adobe.com/flex/3/html/03_Language_and_Syntax_05.html#151506
class PrivateConstructorToken
{
}
